#include "MisDatos.h"

#include "../includes.h"
#include "../../src/recursoDeAlmacenamiento/RecursoDeAlmacenamientoIndexado.h"
#include "../../src/recursoDeAlmacenamiento/FabricaRecursosAlmacenamiento.h"
#include "../../src/indices/IndiceHash.h"
#include "ExtractorClaveRegFijos.h"
#include "ExtractorClaveRegVariable.h"
#include "../../src/estrategiaAlmacenamiento/IteradorBloques.h"
#include "../../src/estrategiaAlmacenamiento/IteradorRegistrosFijos.h"
#include "../../src/indices/IndiceArbol.h"
#include "../../src/Bytes.h"

#include <iostream>
using namespace std;

MisDatos::MisDatos() {

	this->recurso1 = NULL;
	this->recurso2 = NULL;
}

MisDatos::~MisDatos() {

}

void MisDatos::inicializarArchivo1(std::string path, int longitudBloque,
		bool tieneBuffer, int longitudBuffer, bool tieneIndice,
		TipoIndice tipo, int longitudBloqueIndice) throw (ExcepcionMisDatos) {

	tipo_estrategia_recurso buffer;
	if (tieneBuffer) {
		 buffer = DIRECTA;
	} else {
		 buffer = SIN_BUFFER;
	}

	if (recurso1 != NULL) {
		cerr << "InicializarArchivo1::ERROR: el recurso no es NULL";
		delete recurso1;
	}

	system("rm MiArchivo1*");
	if (tipo == HASH) {
		recurso1
				= FabricaRecursosAlmacenamiento::getFabrica()->crearRecursoIndexadoBloques(
						path,
						longitudBloque,
						new IndiceHash(path, new ExtractorClaveRegVariable(), longitudBloqueIndice),
						DIFERIDA, FABRICA_BLOQUES_COMPRIMIDOS);
	} else {
		cantBytes claveMax = 20; // Definido por el usuario
		int orden = longitudBloqueIndice / claveMax;
		recurso1
				= FabricaRecursosAlmacenamiento::getFabrica()->crearRecursoIndexadoBloques(
						path,
						longitudBloque,
						new IndiceArbol(new ExtractorClaveRegVariable(), path, claveMax, orden),
						buffer, FABRICA_BLOQUES_COMPRIMIDOS);
	}
}

void MisDatos::inicializarArchivo2(std::string path, bool tieneBuffer,
		int longitudBuffer, bool tieneIndice, TipoIndice tipo,
		int longitudBloqueIndice) throw (ExcepcionMisDatos) {

	tipo_estrategia_recurso buffer;
	if (tieneBuffer) {
		 buffer = DIRECTA;
	} else {
		 buffer = SIN_BUFFER;
	}

	if (recurso2 != NULL) {
		cerr << "InicializarArchivo1::ERROR: el recurso no es NULL";
		delete recurso2;
	}

	//	system("rm MiArchivo2*");
	if (tipo == HASH) {
		recurso2
				= FabricaRecursosAlmacenamiento::getFabrica()->crearRecursoIndexadoRegistros(
						path,
						2 * sizeof(int) + sizeof(char),
						new IndiceHash(path, new ExtractorClaveRegFijos(), longitudBloqueIndice),
						DIFERIDA);
	} else {
		int claveMax = 20; // Definido por el usuario
		int orden = longitudBloqueIndice / claveMax;
		recurso1
				= FabricaRecursosAlmacenamiento::getFabrica()->crearRecursoIndexadoBloques(
						path,
						longitudBloqueIndice,
						new IndiceArbol(new ExtractorClaveRegVariable(), path, claveMax, orden),
						DIFERIDA,FABRICA_BLOQUES_COMPRIMIDOS);
	}
}

void MisDatos::agregarRegistroArchivo1(MiRegistroVariable registro)
		throw (ExcepcionMisDatos) {
	recurso1->guardar(registro.serializarse());
}

void MisDatos::agregarRegistroArchivo2(MiRegistroFijo registro)
		throw (ExcepcionMisDatos) {
	recurso2->guardar(registro.serializarse());
}

void MisDatos::eliminarRegistroArchivo1(std::string clave)
		throw (ExcepcionMisDatos) {
	Key claveAux(new ClaveString(clave));
	recurso1->eliminar(claveAux);
}

void MisDatos::eliminarRegistroArchivo2(int claveInt, char claveChar)
		throw (ExcepcionMisDatos) {
	Key clave(new ClaveInt(claveInt));
	recurso2->eliminar(clave);
}

void MisDatos::modificarRegistroArchivo1(MiRegistroVariable registro)
		throw (ExcepcionMisDatos) {
	recurso1->modificar(registro.serializarse());
}

void MisDatos::modificarRegistroArchivo2(MiRegistroFijo registro)
		throw (ExcepcionMisDatos) {
	recurso2->modificar(registro.serializarse());
}

MiRegistroVariable MisDatos::obtenerRegistroArchivo1(std::string clave)
		throw (ExcepcionMisDatos) {
	Key claveAux(new ClaveString(clave));
	Bytes serializacion = recurso2->cargar(claveAux);
	return MiRegistroVariable(serializacion);
}

MiRegistroFijo MisDatos::obtenerRegistroArchivo2(int claveInt, char claveChar)
		throw (ExcepcionMisDatos) {
	Key clave(new ClaveInt(claveInt));
	Bytes serializacion = recurso2->cargar(clave);
	return MiRegistroFijo(serializacion);
}

void MisDatos::mostrarContenidoBufferArchivo1() {
	recurso1->imprimirBuffer();
}

void MisDatos::mostrarContenidoBufferArchivo2() {
	recurso2->imprimirBuffer();
}

void MisDatos::mostrarIndiceArchivo1() {
	Indice * i = recurso1->getIndice();
	if (i != NULL) {
		i->visualizar();
	} else {
		cout << "El archivo no tiene un indice." << endl;
	}
}

void MisDatos::mostrarIndiceArchivo2() {
	Indice * i = recurso2->getIndice();
	if (i != NULL) {
		i->visualizar();
	} else {
		cout << "El archivo no tiene un indice." << endl;
	}
}

void MisDatos::mostrarDatosArchivo1() {

	IteradorBloques* it = (IteradorBloques*) recurso1->getIterador();

	long numBloque = -1;

	while (it->tieneSiguiente()) {
		long aux = it->getNumBloqueActual();
		Bytes dato = it->getSiguiente();
		MiRegistroVariable reg("id", 0, NULL, 0);

		reg.hidratarse(dato);

		if (aux != numBloque) {
			numBloque = aux;
			cout << endl << "--------Bloque " << numBloque << "-------- "
					<< endl;
		}
		cout << "Clave:" << reg.getMiStringID() << "  Lista:";

		cout << "[";
		for (int i = 0; i < reg.getCantidadElementosLista(); i++) {
			cout << reg.getMiLista()[i];
			if ((i + 1) != reg.getCantidadElementosLista()) {
				cout << ",";
			}
		}
		cout << "]" << endl;

	}

	cout << endl;
	delete it;
}

void MisDatos::mostrarDatosArchivo2() {

	Iterador* it = recurso2->getIterador();

	while (it->tieneSiguiente()) {
		break;
		cout << it->getSiguiente().toString() << endl;
	}

	delete it;
}

void MisDatos::cerrarArchivo1() {

	if (recurso1 != NULL) {
		delete recurso1;
		recurso1 = NULL;
	}
}

void MisDatos::cerrarArchivo2() {

	if (recurso2 != NULL) {
		delete recurso2;
		recurso2 = NULL;
	}
}
